# coding=utf-8
import hashlib
import six
import redis
#生成多个hash函数的实现和求值
#hash表实现和实现对应的映射表
class MultipleHash(object):
	'''根据提供的原始数据 和预定义的多个salt 生成多个hash函数'''
	def __init__(self,salts,hash_func_name="md5"):
		self.hash_func = getattr(hashlib,hash_func_name)
		if len(salts)<3:
			raise Exception("请提供3个salts")
		self.salts=salts

	def get_hash_values(self ,data):
		hash_values=[]
		for i in self.salts:
			hash_obj = self.hash_func()
			hash_obj.update(self._safe_data(data))
			hash_obj.update(self._safe_data(i))
			ret = hash_obj.hexdigest()
			hash_values.append(int(ret,16))

		return hash_values

	def _safe_data(self,data):
		'''
			py2 str ===py3 bytes
			py2 unicode ===py3 str
			param data 给定的原始数据
			return 二进制的字符串数据
		'''
		if six.PY3:
			if isinstance(data,bytes):
				return data
			elif isinstance(data,str):
				return data.encode()
			else:
				raise Exception("请提供一个字符串")

		else:
			if isinstance(data,str):
				return data
			elif isinstance(data,unicode):
				return data.encode
			else:
				raise Exception("请提供一个字符串")
class BloomFilter(object):
	def __init__(self ,salts,redis_host ="127.0.0.1",redis_port=6379 ,redis_db=0):
		# self.redis_host =redis_host
		# self.redis_port = redis_port
		# self.redis_db = redis_db
		self.redis_key="bloomfilter001"
		self.client = self._get_redis_client()
		self.multiple_hash = MultipleHash(salts)
	def _get_redis_client(self):
		pool=redis.ConnectionPool(host="127.0.0.1",port="6379",db="")
		client = redis.StrictRedis(connection_pool=pool)
		return client

	def save(self ,data):
		hash_values = self.multiple_hash.get_hash_values(data)
		for hval in hash_values:
			offset = self._get_offset(hval)
			print(offset)
			self.client.setbit(self.redis_key,offset,1)
		return True
	
	def _get_offset(self,hash_value):
		'''
		计算长度 512M的长度 512*1024*1024*8 哈希表长度
		2**8 =256
		2**29=1024 *1024

		'''
		return hash_value %2**9 * 2**20 * 2*3

	def is_existes(self, data):
		hash_values = self.multiple_hash.get_hash_values(data)
		for hval in hash_values:
			offset = self._get_offset(hval)
			v = self.client.getbit(self.redis_key,offset)
			if v==0:
				return False
		return True




if __name__ == '__main__':

	# print("汉法")
	# exit(1)
	# mh = MultipleHash(["1","2","3"])
	# print(mh.get_hash_values("afadfauegasdg"))
	data = ["adfadf","123","123","242","fsdf"]
	salts = ['1','2','3']
	bm = BloomFilter(salts)
	for d in data:
		if not bm.is_existes(d):
			bm.save(d)
			print("映射成功 ：%s"%d)
		else:
			print("发现重复数据：%s"%d)